
package com.rt.schedulenew.utils.pkgenerator;
import java.util.HashMap;
import java.util.Date;
import java.util.concurrent.locks.ReentrantLock;
import java.util.Map;
import java.text.SimpleDateFormat;
import java.util.concurrent.locks.Lock;
public class PKGeneratorSingle
{
    private final Lock LOCK;
    private static final Long START_MILLI;
    private static final long START_NANO;
    private volatile long lastPK;
    private static final SimpleDateFormat DATE_FORMAT;
    private int suffix;
    private static final Map<Integer, PKGeneratorSingle> INSTANCE_MAP;
    
    private PKGeneratorSingle(final int suffix) {
        this.LOCK = new ReentrantLock();
        this.lastPK = -1L;
        this.suffix = 0;
        this.suffix = suffix;
    }
    
    public static synchronized PKGeneratorSingle getInstance() {
        return getInstance(0);
    }
    
    public static synchronized PKGeneratorSingle getInstance(final int suffix) {
        PKGeneratorSingle pkgen;
        if (!PKGeneratorSingle.INSTANCE_MAP.containsKey(suffix)) {
            pkgen = new PKGeneratorSingle(suffix);
            PKGeneratorSingle.INSTANCE_MAP.put(suffix, pkgen);
        }
        else {
            pkgen = PKGeneratorSingle.INSTANCE_MAP.get(suffix);
        }
        return pkgen;
    }
    
    public long nextPK() {
        this.LOCK.lock();
        try {
            long newPK;
            do {
                final long pastNano = System.nanoTime() - PKGeneratorSingle.START_NANO;
                final long milliTime = pastNano / 1000000L;
                final long macroTime = pastNano / 100000L % 10L;
                newPK = Long.parseLong(PKGeneratorSingle.DATE_FORMAT.format(new Date(PKGeneratorSingle.START_MILLI + milliTime)) + macroTime + this.suffix);
            } while (this.lastPK == newPK);
            return this.lastPK = newPK;
        }
        finally {
            this.LOCK.unlock();
        }
    }
    
    public String nextPKStr() {
        this.LOCK.lock();
        try {
            long newPK;
            do {
                final long pastNano = System.nanoTime() - PKGeneratorSingle.START_NANO;
                final long milliTime = pastNano / 1000000L;
                final long macroTime = pastNano / 100000L % 10L;
                newPK = Long.parseLong(PKGeneratorSingle.DATE_FORMAT.format(new Date(PKGeneratorSingle.START_MILLI + milliTime)) + macroTime + this.suffix);
            } while (this.lastPK == newPK);
            this.lastPK = newPK;
            return String.valueOf(newPK);
        }
        finally {
            this.LOCK.unlock();
        }
    }
    
    static {
        START_MILLI = System.currentTimeMillis();
        START_NANO = System.nanoTime();
        DATE_FORMAT = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        INSTANCE_MAP = new HashMap<Integer, PKGeneratorSingle>();
    }
}
